#region License
// Copyright 2007-2008 Rory Plaire (codekaizen@gmail.com)
/*
 * This license governs use of the accompanying software. If you use the software, you
 * accept this license. If you do not accept the license, do not use the software.
 * 
 * 1. Definitions
 * The terms "reproduce," "reproduction," "derivative works," and "distribution" have the
 * same meaning here as under U.S. copyright law.
 * A "contribution" is the original software, or any additions or changes to the software.
 * A "contributor" is any person that distributes its contribution under this license.
 * "Licensed patents" are a contributor's patent claims that read directly on its contribution.
 * 
 * 2. Grant of Rights
 * (A) Copyright Grant- Subject to the terms of this license, including the license conditions 
 *     and limitations in section 3, each contributor grants you a non-exclusive, worldwide, 
 *     royalty-free copyright license to reproduce its contribution, prepare derivative works 
 *     of its contribution, and distribute its contribution or any derivative works that you create.
 * (B) Patent Grant- Subject to the terms of this license, including the license conditions and 
 *     limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free 
 *     license under its licensed patents to make, have made, use, sell, offer for sale, import, 
 *     and/or otherwise dispose of its contribution in the software or derivative works of the 
 *     contribution in the software.
 * 
 * 3. Conditions and Limitations
 * (A) No Trademark License- This license does not grant you rights to use any contributors' 
 *     name, logo, or trademarks.
 * (B) If you bring a patent claim against any contributor over patents that you claim are 
 *     infringed by the software, your patent license from such contributor to the software 
 *     ends automatically.
 * (C) If you distribute any portion of the software, you must retain all copyright, patent, 
 *     trademark, and attribution notices that are present in the software.
 * (D) If you distribute any portion of the software in source code form, you may do so only under 
 *     this license by including a complete copy of this license with your distribution. If you 
 *     distribute any portion of the software in compiled or object code form, you may only do so 
 *     under a license that complies with this license.
 * (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no 
 *     express warranties, guarantees or conditions. You may have additional consumer rights under 
 *     your local laws which this license cannot change. To the extent permitted under your local laws, 
 *     the contributors exclude the implied warranties of merchantability, fitness for a particular 
 *     purpose and non-infringement.
 * 
 */
#endregion

using System;
using NPack.Matrix;
using Xunit;
using IMatrixD = NPack.Interfaces.IMatrix<NPack.DoubleComponent>;
using LuDecompositionD = NPack.LUDecomposition<NPack.DoubleComponent, NPack.Matrix.Matrix<NPack.DoubleComponent>>;
using LuDecompositionF = NPack.LUDecomposition<NPack.SingleComponent, NPack.Matrix.Matrix<NPack.SingleComponent>>;
using MatrixF = NPack.Matrix.Matrix<NPack.SingleComponent>;
using MatrixD = NPack.Matrix.Matrix<NPack.DoubleComponent>;

namespace NPack.Tests
{
    public class LUDecompositionTests
    {
        private LinearFactory<DoubleComponent> _doubleFactory = new LinearFactory<DoubleComponent>();
        private LinearFactory<SingleComponent> _singleFactory = new LinearFactory<SingleComponent>();

        [Fact]
        public void LUFactorizationCorrectnessTest()
        {
            MatrixD m1 = MatrixD.CreateRandom(MatrixFormat.ColumnMajor, 3, 3);

            LuDecompositionD lu1 = new LuDecompositionD(m1, _doubleFactory);

            MatrixD m2 = lu1.Pivot.Multiply(m1);

            Assert.Equal(m2.ToString(), lu1.L.Multiply(lu1.U).ToString());
        }

        [Fact]
        public void NoNullReferenceAcceptedInConstructor()
        {
            Assert.Throws<ArgumentNullException>(delegate() { new LuDecompositionD(null, _doubleFactory); });
		}


		[Fact]
		public void ConstructorMatrixShouldBeEqualButNotSameAsInputMatrix()
		{
            MatrixF m1 = MatrixF.CreateRandom(MatrixFormat.ColumnMajor, 4, 4);
			LuDecompositionF lu1 = new LuDecompositionF(m1, _singleFactory);
			Assert.Equal(m1, lu1.InputMatrix);
			Assert.NotSame(m1, lu1.InputMatrix);
		}


		[Fact]
		public void DeterminantIsNotComputableForNonSquareMatrixes()
		{
            MatrixF m1 = MatrixF.CreateRandom(MatrixFormat.ColumnMajor, 3, 4);
            LuDecompositionF lu1 = new LuDecompositionF(m1, _singleFactory);

			Assert.Throws<InvalidOperationException>(delegate() { Double value = lu1.Determinant; });
		}

		[Fact]
		public void SolutionCannotBeComputedForNullReference()
		{
            MatrixF m1 = MatrixF.CreateRandom(MatrixFormat.ColumnMajor, 3, 3);
			LuDecompositionF lu1 = new LuDecompositionF(m1, _singleFactory);
			Assert.Throws<ArgumentNullException>(delegate() { lu1.Solve(null); });
		}

		[Fact]
		public void SolutionCannotBeComputedForMatrixOfDifferentRowRankThanInput()
		{
            MatrixF m1 = MatrixF.CreateRandom(MatrixFormat.ColumnMajor, 3, 3);
            MatrixF m2 = MatrixF.CreateRandom(MatrixFormat.ColumnMajor, 2, 3);
            LuDecompositionF lu1 = new LuDecompositionF(m1, _singleFactory);
			Assert.Throws<ArgumentException>(delegate() { lu1.Solve(m2); });
		}

		[Fact]
		public void SolutionCannotBeFoundForSingluarInputMatrix()
		{
            MatrixF m1 = MatrixF.CreateRandom(MatrixFormat.ColumnMajor, 3, 3);

			// Make singluar
			m1[2, 0] = 0.0F;
			m1[2, 1] = 0.0F;
			m1[2, 2] = 0.0F;

            MatrixF m2 = MatrixF.CreateRandom(MatrixFormat.ColumnMajor, 3, 3);

			Assert.True(m1.IsSingular);

            LuDecompositionF lu1 = new LuDecompositionF(m1, _singleFactory);

			Assert.Throws<InvalidOperationException>(delegate() { lu1.Solve(m2); });
		}
    }
}
